/**
 * @file arrays.h
 *
 * Support of array/matrix operations
 *
 * In current version, it is based on Eigen 3
 * 
 * @author Dahua Lin
 */

#ifndef SLIPP_ARRAYS_H_
#define SLIPP_ARRAYS_H_

#include <slipp/eigen_ex/eigen_common.h>
#include <slipp/eigen_ex/eigen_share.h>
#include <slipp/eigen_ex/eigen_algorithms.h>
#include <slipp/eigen_ex/eigen_efuns.h>


#define SLI_AROW(T) Eigen::Array<T, 1, Eigen::Dynamic>
#define SLI_ACOL(T) Eigen::Array<T, Eigen::Dynamic, 1>
#define SLI_ARR(T) Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic>

#define SLI_VROW(T) Eigen::Matrix<T, 1, Eigen::Dynamic>
#define SLI_VCOL(T) Eigen::Matrix<T, Eigen::Dynamic, 1>
#define SLI_MAT(T) Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>

#define SLI_SAROW(T) eigen_share_array<T, 1, Eigen::Dynamic>
#define SLI_SACOL(T) eigen_share_array<T, Eigen::Dynamic, 1>
#define SLI_SARR(T) eigen_share_array<T, Eigen::Dynamic, Eigen::Dynamic>

#define SLI_SVROW(T) eigen_share_matrix<T, 1, Eigen::Dynamic>
#define SLI_SVCOL(T) eigen_share_matrix<T, Eigen::Dynamic, 1>
#define SLI_SMAT(T) eigen_share_matrix<T, Eigen::Dynamic, Eigen::Dynamic>

namespace sli
{
	typedef SLI_AROW(double) darow_t;
	typedef SLI_ACOL(double) dacol_t;
	typedef SLI_ARR(double)  darr_t;
	typedef SLI_VROW(double) dvrow_t;
	typedef SLI_VCOL(double) dvcol_t;
	typedef SLI_MAT(double)  dmat_t;

	typedef SLI_AROW(float) farow_t;
	typedef SLI_ACOL(float) facol_t;
	typedef SLI_ARR(float)  farr_t;
	typedef SLI_VROW(float) fvrow_t;
	typedef SLI_VCOL(float) fvcol_t;
	typedef SLI_MAT(float)  fmat_t;

	typedef SLI_AROW(int32_t) iarow_t;
	typedef SLI_ACOL(int32_t) iacol_t;
	typedef SLI_ARR(int32_t)  iarr_t;
	typedef SLI_VROW(int32_t) ivrow_t;
	typedef SLI_VCOL(int32_t) ivcol_t;
	typedef SLI_MAT(int32_t)  imat_t;

	typedef SLI_AROW(uint32_t) uarow_t;
	typedef SLI_ACOL(uint32_t) uacol_t;
	typedef SLI_ARR(uint32_t)  uarr_t;
	typedef SLI_VROW(uint32_t) uvrow_t;
	typedef SLI_VCOL(uint32_t) uvcol_t;
	typedef SLI_MAT(uint32_t)  umat_t;

	typedef SLI_AROW(bool) barow_t;
	typedef SLI_ACOL(bool) bacol_t;
	typedef SLI_ARR(bool)  barr_t;
	typedef SLI_VROW(bool) bvrow_t;
	typedef SLI_VCOL(bool) bvcol_t;
	typedef SLI_MAT(bool)  bmat_t;

	typedef SLI_SAROW(double) share_darow_t;
	typedef SLI_SACOL(double) share_dacol_t;
	typedef SLI_SARR(double)  share_darr_t;
	typedef SLI_SVROW(double) share_dvrow_t;
	typedef SLI_SVCOL(double) share_dvcol_t;
	typedef SLI_SMAT(double)  share_dmat_t;

	typedef SLI_SAROW(float) share_farow_t;
	typedef SLI_SACOL(float) share_facol_t;
	typedef SLI_SARR(float)  share_farr_t;
	typedef SLI_SVROW(float) share_fvrow_t;
	typedef SLI_SVCOL(float) share_fvcol_t;
	typedef SLI_SMAT(float)  share_fmat_t;

	typedef SLI_SAROW(int32_t) share_iarow_t;
	typedef SLI_SACOL(int32_t) share_iacol_t;
	typedef SLI_SARR(int32_t)  share_iarr_t;
	typedef SLI_SVROW(int32_t) share_ivrow_t;
	typedef SLI_SVCOL(int32_t) share_ivcol_t;
	typedef SLI_SMAT(int32_t)  share_imat_t;

	typedef SLI_SAROW(uint32_t) share_uarow_t;
	typedef SLI_SACOL(uint32_t) share_uacol_t;
	typedef SLI_SARR(uint32_t)  share_uarr_t;
	typedef SLI_SVROW(uint32_t) share_uvrow_t;
	typedef SLI_SVCOL(uint32_t) share_uvcol_t;
	typedef SLI_SMAT(uint32_t)  share_umat_t;

	typedef SLI_SAROW(bool) share_barow_t;
	typedef SLI_SACOL(bool) share_bacol_t;
	typedef SLI_SARR(bool)  share_barr_t;
	typedef SLI_SVROW(bool) share_bvrow_t;
	typedef SLI_SVCOL(bool) share_bvcol_t;
	typedef SLI_SMAT(bool)  share_bmat_t;


	// convenient functions

	template<typename T>
	inline SLI_ARR(T) make_arr(index_t m, index_t n, const T *data=SLI_NULL)
	{
		SLI_ARR(T) r(m, n);
		if (data) std::copy_n(data, (size_t)(m * n), r.data());
		return r;
	}

	template<typename T>
	inline SLI_AROW(T) make_arow(index_t n, const T *data=SLI_NULL)
	{
		SLI_AROW(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}

	template<typename T>
	inline SLI_ACOL(T) make_acol(index_t n, const T *data=SLI_NULL)
	{
		SLI_ACOL(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}

	template<typename T>
	inline SLI_MAT(T) make_mat(index_t m, index_t n, const T *data=SLI_NULL)
	{
		SLI_MAT(T) r(m, n);
		if (data) std::copy_n(data, (size_t)(m * n), r.data());
		return r;
	}

	template<typename T>
	inline SLI_VROW(T) make_vrow(index_t n, const T *data=SLI_NULL)
	{
		SLI_VROW(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}

	template<typename T>
	inline SLI_VCOL(T) make_vcol(index_t n, const T *data=SLI_NULL)
	{
		SLI_VCOL(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}


	template<typename T>
	SLI_SARR(T) make_share_arr(index_t m, index_t n, const T *data=SLI_NULL)
	{
		SLI_SARR(T) r(m, n);
		if (data) std::copy_n(data, (size_t)(m * n), r.data());
		return r;
	}

	template<typename T>
	inline SLI_SAROW(T) make_share_arow(index_t n, const T *data=SLI_NULL)
	{
		SLI_SAROW(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}

	template<typename T>
	inline SLI_SACOL(T) make_share_acol(index_t n, const T *data=SLI_NULL)
	{
		SLI_SACOL(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}

	template<typename T>
	inline SLI_SMAT(T) make_share_mat(index_t m, index_t n, const T *data=SLI_NULL)
	{
		SLI_SMAT(T) r(m, n);
		if (data) std::copy_n(data, (size_t)(m * n), r.data());
		return r;
	}

	template<typename T>
	inline SLI_SVROW(T) make_share_vrow(index_t n, const T *data=SLI_NULL)
	{
		SLI_SVROW(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}

	template<typename T>
	inline SLI_SVCOL(T) make_share_vcol(index_t n, const T *data=SLI_NULL)
	{
		SLI_SVCOL(T) r(n);
		if (data) std::copy_n(data, (size_t)n, r.data());
		return r;
	}


	template<class Derived>
	eigen_share_array<typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime>
	share_copy(const Eigen::ArrayBase<Derived>& a)
	{
		typedef eigen_share_array<typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime> ty;
		return ty(a.derived());
	}

	template<class Derived>
	eigen_share_matrix<typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime>
	share_copy(const Eigen::MatrixBase<Derived>& a)
	{
		typedef eigen_share_matrix<typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime> ty;
		return ty(a.derived());
	}

}

#endif 


